<?php
// If it's going to need the database, then it's
// probably smart to require it before we start.
require_once(LIB_PATH.DS.'database.php');


class DatabaseObject
 {
	 public $id;
	 public $username;
	 public $password;
	 public $first_name;
	 public $last_name;
	 protected static $table_name;
	 
	 
// common database methods.  Moved from users class.
	 public static function find_all()
	  {
		return static::find_by_sql("SELECT * FROM ".static::$table_name);  // PHP v5.3
	  }
	  
	 public static function find_by_id($id=0)
	  {
		global $database;
		// static:: instead of self:: calls late static bindings in PHP 5.3
		// self will call the parent class whereas static will call the instantiating class
		$result_array = static::find_by_sql("SELECT * FROM ". static::$table_name . " WHERE id=".$database->escape_value($id)." LIMIT 1");
		return !empty($result_array) ? array_shift($result_array) : false;   
	  }
	 
	 public static function find_by_sql($sql="")
	  {
		global $database;
		$result_set = $database->query($sql);
		$object_array = array();
		while ($row = $database->fetch_array($result_set))
		 {
			$object_array[] = static::instantiate($row); 
		 }
		return $object_array;  
	  }
	  
	 public static function count_all()
	  {
		global $database;
		$sql = "SELECT COUNT(*) FROM ".static::$table_name;
		$result_set = $database->query($sql);	// returns a number inside a row
		$row = $database->fetch_array($result_set);
		return array_shift($row);  				// pulls the number out of the row
	  }
	  
	 private static function instantiate($record)
	  {
		// long way
		$called_class = get_called_class();
		$object = new $called_class;
//		$object->id 		= $record['id'];
//		$object->username 	= $record['username'];
//		$object->password 	= $record['password'];
//		$object->first_name = $record['first_name'];
//		$object->last_name 	= $record['last_name'];
		
		// More dynamic, short way
		foreach($record as $attribute=>$value)
		 {
			if($object->has_attribute($attribute)) 
			 {
				$object->$attribute = $value; 
			 }
		 }
		 
		return $object;
	  }
	  
	 private function has_attribute($attribute)
	  {
		// get_object_vars returns an assoc. array with all attributes
		// (incl. private) as the keys and their current values as the value
		$object_vars = $this->attributes();
		// we don't care about the value, we just want to know if the key exists
		// boolean return
		return array_key_exists($attribute, $object_vars);  
	  }
	 
	 protected function attributes()	// returns raw attributes
	  {
		// return an array of attribute keys and their values
		//return get_object_vars($this);  	// includes private and protected ones -> not good
		// better:
		$attributes = array();
		foreach(static::$db_fields as $field)
		 {
			if(property_exists($this, $field))
			 {
				 $attributes[$field] = $this->$field; 	// dynamic field
			 }
		 }
		return $attributes;
	  }
	  
	 protected function sanitized_attributes()		// returns cleaded attributes
	  {
		global $database;
		$clean_attributes = array();
		// sanitize the values before submitting
		// NOTE: does not alter the actual value of each attribute
		foreach($this->attributes() as $key => $value)
		 {
			$clean_attributes[$key] = $database->escape_value($value); 
		 }
		 return $clean_attributes;
	  }

	 public function save()
	  {
		  // A new record won't have an id yet.
		  return isset($this->id) ? $this->update() : $this->create();
	  }
	  
	 public function destroy()
	  {
		// first remove the database entry
		if($this->delete())
		 {
			// then remove the file
			// Note: even though the database entry is gone, this object
			// is still around (which lets us use $this->image_path();
			$target_path = SITE_ROOT.DS.'public'.DS.$this->image_path();
			return unlink($target_path) ? true : false; 
		 } else {
			 // database delte failed
			 return false;
		 }
	  }
	 
	 protected function create()
	  {
		  global $database;
		  // don't forget your SQL syntax and good habits:
		  // INSERT INTO table (key, key) VALUES ('value', 'value')
		  // single quotes around all values
		  // escape all values to prevent SQL injection
		  $attributes = $this->sanitized_attributes();
		  $sql = "INSERT INTO " . static::$table_name . " (";
		  $sql .= join(", ", array_keys($attributes));		// attribute keys
		  $sql .= ") VALUES ('";
		  $sql .= join("', '", array_values($attributes));	// attribute values
		  $sql .= "')";
		  if($database->query($sql))
		   {
			$this->id = $database->insert_id();
			return true; 
		   } else { return false;}
	  }
	  
	 protected function update()
	  {
		 global $database;
		 // don't forget your SQL syntax and good habits:
		 // - UPDATE table SET key='value', key='value' WHERE condition
		 // - single-quotes around all values
		 // - escape all values to prevent SQL injection
		 $attributes = $this->sanitized_attributes();
		 $attribute_pairs = array();
		 foreach($attributes as $key => $value)
		  {
			$attribute_pairs[] = "{$key} = '{$value}'";  
		  }
		 $sql = "UPDATE " . self::$table_name . " SET ";
		 $sql .= join(", ", $attribute_pairs);
		 // MUST have space before WHERE
		 $sql .= " WHERE id=". $database->escape_value($this->id);
		 $database->query($sql);
		 return($database->affected_rows() == 1) ? true : false;
	  }

	 public function delete()
	 {
		global $database;
		// Don't forget your SQL syntax and good habits:
		// - DELETE FROM table WHERE condition LIMIT 1
		// - escape all values to prevent SQL injection
		// - use LIMIT 1
		$sql = "DELETE FROM " . static::$table_name;
		$sql .= " WHERE id=" . $database->escape_value($this->id); 
		$sql .= " LIMIT 1";
		$database->query($sql);
		return($database->affected_rows() == 1) ? true : false;
	 }
 
	  
	  
	  
	  
 }


?>